package com.ews.onlineexchange.exception;

import java.util.Iterator;

import javax.enterprise.deploy.spi.exceptions.TargetException;
import javax.faces.FacesException;
import javax.faces.context.ExceptionHandler;
import javax.faces.context.ExceptionHandlerWrapper;
import javax.faces.context.FacesContext;
import javax.faces.event.ExceptionQueuedEvent;
import javax.faces.event.ExceptionQueuedEventContext;
import javax.persistence.OptimisticLockException;

import org.hibernate.StaleObjectStateException;

public class OptimisticLockExceptionHandler extends ExceptionHandlerWrapper {

	private ExceptionHandler wrapped;

    public OptimisticLockExceptionHandler(ExceptionHandler wrapped) {
        this.wrapped = wrapped;
    }

    @Override
    public ExceptionHandler getWrapped() {
        return this.wrapped;
    }
    
    @Override
    public void handle()
            throws FacesException {

        for (Iterator<ExceptionQueuedEvent> i =
                getUnhandledExceptionQueuedEvents().iterator();
                i.hasNext();) {
            ExceptionQueuedEvent event = i.next();
            ExceptionQueuedEventContext context =
                    (ExceptionQueuedEventContext) event.getSource();
            Throwable t = getCause(context.getException(), OptimisticLockException.class);            
            String cause = t.toString();
            
            if (t instanceof StaleObjectStateException
                    || t instanceof OptimisticLockException || cause.indexOf("Row was updated or deleted by another transaction") !=-1) {

                FacesContext fc = FacesContext.getCurrentInstance();
                try {

                    if (!fc.getExternalContext().isResponseCommitted()) {
                    	
                        fc.getExternalContext().redirect(fc.getExternalContext().getApplicationContextPath()+"/OptimisticLockExceptionView.xhtml");
                    }
                    fc.renderResponse();
                    break;
                } catch (Exception ex) {
                    throw new FacesException(ex);
                } finally {
                    i.remove();
                }
            }
        }
        getWrapped().handle();
    }
    
    public Throwable getCause(Throwable t, Class<OptimisticLockException> targetExceptionClass) {
    	  if (t.getClass().equals(targetExceptionClass)) {
    		  return t;
    	  } else {
    		  try {
				Thread.sleep(200);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				//e.printStackTrace();
			}
    		  return getCause(t.getCause(), targetExceptionClass);    		  
    	  }
    }
}
